package me.exchange.com.modules.system.service.impl;

import me.exchange.com.exception.EntityExistException;
import me.exchange.com.exception.EntityNotFoundException;
import me.exchange.com.modules.system.domain.Role;
import me.exchange.com.modules.system.domain.User;
import me.exchange.com.modules.system.dto.UserDto;
import me.exchange.com.modules.system.dto.UserQueryCriteria;
import me.exchange.com.modules.system.mapper.UserMapper;
import me.exchange.com.modules.system.repository.DeptRepository;
import me.exchange.com.modules.system.repository.RoleRepository;
import me.exchange.com.modules.system.repository.UserRepository;
import me.exchange.com.modules.system.service.UserService;
import me.exchange.com.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.*;

/**
 * @author Zheng Jie
 * @date 2018-11-23
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private DeptRepository deptRepository;

    @Value("${file.avatar}")
    private String avatar;

    public UserServiceImpl(UserRepository userRepository, UserMapper userMapper, RedisUtils redisUtils,
                           RoleRepository roleRepository, DeptRepository deptRepository) {
        this.userRepository = userRepository;
        this.userMapper = userMapper;
        this.redisUtils = redisUtils;
        this.roleRepository = roleRepository;
        this.deptRepository = deptRepository;
    }

    @Override
    public Map<String,Object> queryAll(UserQueryCriteria criteria, Pageable pageable) {
        Page<User> page = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        Map<String,Object> userInfo= PageUtil.toPage(page.map(userMapper::toDto));
        List<UserDto> new_obj = (List<UserDto>)userInfo.get("content");
        userInfo.put("content",new_obj);
        return userInfo;
    }

    @Override
    public List<UserDto> queryAll(UserQueryCriteria criteria) {
        Sort sort = criteria.getSort();
        List<User> users = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),sort);
        return userMapper.toDto(users);
    }


    @Override
    public UserDto findById(long id) {
        User user = userRepository.findById(id).orElseGet(User::new);
        ValidationUtil.isNull(user.getId(),"User","id",id);
        return userMapper.toDto(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDto create(User resources) {
        if(userRepository.findByUsername(resources.getUsername())!=null){
            throw new EntityExistException(User.class,"username",resources.getUsername());
        }
        if(userRepository.findByEmail(resources.getEmail())!=null){
            throw new EntityExistException(User.class,"email",resources.getEmail());
        }
        User user=userRepository.findByUsername(SecurityUtils.getUsername());
        resources.setCAdminId(user.getId());
        resources.setCAdminTime(new Timestamp(System.currentTimeMillis()));
        resources.setIsdel(true);
        return userMapper.toDto(userRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(User resources) {
        User su_user=userRepository.findByUsername(SecurityUtils.getUsername());
        User user = userRepository.findById(resources.getId()).orElseGet(User::new);
        ValidationUtil.isNull(user.getId(),"User","id",resources.getId());
        User user1 = userRepository.findByUsername(user.getUsername());
        User user2 = userRepository.findByEmail(user.getEmail());

        if(user1 !=null&&!user.getId().equals(user1.getId())){
            throw new EntityExistException(User.class,"username",resources.getUsername());
        }

        if(user2!=null&&!user.getId().equals(user2.getId())){
            throw new EntityExistException(User.class,"email",resources.getEmail());
        }

        // 如果用户的角色改变了，需要手动清理下缓存
        if (!resources.getRoleId().equals(user.getRoleId())) {
            String key = "role::loadPermissionByUser:" + user.getUsername();
            redisUtils.del(key);
            key = "role::findByUsers_Id:" + user.getId();
            redisUtils.del(key);
        }
        resources =(User)BeanUtil.merge(resources,user);
        resources.setUAdminId(su_user.getId());
        resources.setUAdminTime(new Timestamp(System.currentTimeMillis()));
        userRepository.save(resources);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCenter(User resources) {
        User su_user=userRepository.findByUsername(SecurityUtils.getUsername());
        User user = userRepository.findById(resources.getId()).orElseGet(User::new);
        resources =(User)BeanUtil.merge(resources,user);
        resources.setUAdminId(su_user.getId());
        resources.setUAdminTime(new Timestamp(System.currentTimeMillis()));
        userRepository.save(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Set<Long> ids) {
        User del_user = null;
        for (Long id : ids) {
            del_user = userRepository.findById(id).orElseGet(User::new);
            del_user.setIsdel(false);
            userRepository.save(del_user);
            //userRepository.deleteById(id);
        }
    }

    @Override
    public UserDto findByName(String userName) {
        User user;
        if(ValidationUtil.isEmail(userName)){
            user = userRepository.findByEmail(userName);
        } else {
            user = userRepository.findByUsername(userName);
        }
        if (user == null) {
            throw new EntityNotFoundException(User.class, "name", userName);
        } else {
            return userMapper.toDto(user);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateGoogleKey(UserDto userDto){
        userRepository.save(userMapper.toEntity(userDto));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePass(String username, String pass) {
        userRepository.updatePass(username,pass,new Date());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateEmail(String username, String email) {
        userRepository.updateEmail(username,email);
    }

    @Override
    public void download(List<UserDto> queryAll, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (UserDto userDTO : queryAll) {

            Role roles = roleRepository.findById(userDTO.getRoleId()).orElseGet(Role::new);
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("用户名", userDTO.getUsername());
            map.put("头像", userDTO.getAvatarPath());
            map.put("邮箱", userDTO.getEmail());
            map.put("状态", userDTO.getEnabled() ? "启用" : "禁用");
            map.put("手机号码", userDTO.getPhone());
            map.put("角色", roles.getRoleName());
            map.put("部门", userDTO.getDept().getName());
            map.put("最后修改密码的时间", userDTO.getLastPasswordResetTime());
            map.put("创建日期", userDTO.getCAdminTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

}
